package jwlee.testfile;

/** 

 ** @作者 张华 

 ** @时间 2008-6-19 下午12:28:35 

 ** @描述 http://www.chinajavaworld.com/message.jspa?messageID=731691 

 *    在XP下如果报错：Exception in thread "main" java.lang.UnsatisfiedLinkError: C:\WINDOWS\system32\jacob-1.14-x86.dll: 由于应用程序配置不正确，应用程序未能启动。重新安装应用程序可能会纠正这个问题 

 *    则需要下载Microsoft Visual C++ 2005 SP1 Redistributable Package (x86) 

 *    参考网页:http://203.208.37.104/search?q=cache:gj03bbrQsKkJ:fishbottle.javaeye.com/blog/175191+java.lang.UnsatisfiedLinkError:+C:%5CWINDOWS%5Csystem32%5Cjacob-1.14-x86.dll:+%E7%94%B1%E4%BA%8E%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E9%85%8D%E7%BD%AE%E4%B8%8D%E6%AD%A3%E7%A1%AE%EF%BC%8C%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E6%9C%AA%E8%83%BD%E5%90%AF%E5%8A%A8%E3%80%82%E9%87%8D%E6%96%B0%E5%AE%89%E8%A3%85%E5%BA%94%E7%94%A8%E7%A8%8B%E5%BA%8F%E5%8F%AF%E8%83%BD%E4%BC%9A%E7%BA%A0%E6%AD%A3%E8%BF%99%E4%B8%AA%E9%97%AE%E9%A2%98%E3%80%82&hl=zh-CN&ct=clnk&cd=1&gl=cn&st_usg=ALhdy2_NtVF_vsJEcITmJWhaKmWAB-QPVw 

 *    但是目前在2003下还是会报，尚未解决：com.jacob.com.ComFailException：Can't get object clsid from progid 

 **/

import java.io.File;
import java.util.HashMap;

import java.util.Iterator;

import java.util.List;

import com.jacob.activeX.ActiveXComponent;

import com.jacob.com.Dispatch;

import com.jacob.com.Variant;

public class TestWord {

	private boolean saveOnExit;

	/**
	 * 
	 * word文档
	 */

	Dispatch doc = null;

	/**
	 * 
	 * word运行程序对象
	 */

	private ActiveXComponent word;

	/**
	 * 
	 * 所有word文档
	 */

	private Dispatch documents;

	public void init() {
		try {
			// 问题：http://forum.java.sun.com/thread.jspa?threadID=5274500

			// http://www.blogjava.net/lusm/archive/2008/05/17/106737.html

			// http://zhidao.baidu.com/question/36063206.html?fr=qrl

			// http://linder0209.javaeye.com/blog/202516

			word = new ActiveXComponent("Word.Application");

		} catch (Exception e) {
			e.printStackTrace();
		}

		documents = word.getProperty("Documents").toDispatch();

		// 显示WORD
		word.setProperty("Visible", new Variant(false));
	}

	/**
	 * 
	 * 构造函数
	 */

	public TestWord() {
		saveOnExit = true;
	}

	/**
	 * 
	 * 打开文件
	 * 
	 * 
	 * 
	 * @param inputDoc
	 * 
	 *            String 要打开的文件，全路径
	 * 
	 * @return Dispatch 打开的文件
	 */

	public Dispatch open(String inputDoc) {
		return Dispatch.call(documents, "Open", inputDoc).toDispatch();
	}

	/**
	 * 
	 * 选定内容
	 * 
	 * 
	 * 
	 * @return Dispatch 选定的范围或插入点
	 */

	public Dispatch select() {
		return word.getProperty("Selection").toDispatch();
	}

	/**
	 * 
	 * 把插入点移动到文件首位置
	 * 
	 * 
	 * 
	 * @param selection
	 * 
	 *            Dispatch 插入点
	 */

	public void moveStart(Dispatch selection) {
		Dispatch.call(selection, "HomeKey", new Variant(6));
	}

	private void moveRight(Dispatch selection, int count) {
		for (int i = 0; i < count; i++)
			Dispatch.call(selection, "MoveRight");
	}

	private void moveUp(Dispatch selection, int count) {
		for (int i = 0; i < count; i++)
			Dispatch.call(selection, "MoveUp");
	}

	private static void moveDown(Dispatch selection, int count) {
		for (int i = 0; i < count; i++)
			Dispatch.call(selection, "MoveDown");
	}

	private void moveLeft(Dispatch selection, int count) {
		for (int i = 0; i < count; i++)
			Dispatch.call(selection, "MoveLeft");
	}

	public void insertln() {
		Dispatch range = Dispatch.get(select(), "Range").toDispatch();

		Dispatch.call(range, "InsertParagraphAfter");

		moveDown(select(), 1);
	}

	/**
	 * 
	 * 从选定内容或插入点开始查找文本
	 * 
	 * 
	 * 
	 * @param selection
	 * 
	 *            Dispatch 选定内容
	 * 
	 * @param toFindText
	 * 
	 *            String 要查找的文本
	 * 
	 * @return boolean true-查找到并选中该文本，false-未查找到文本
	 */

	public boolean find(Dispatch selection, String toFindText) {

		// 从selection所在位置开始查询
		Dispatch find = word.call(selection, "Find").toDispatch();

		// 设置要查找的内容
		Dispatch.put(find, "Text", toFindText);

		// 向前查找
		Dispatch.put(find, "Forward", "True");

		// 设置格式
		Dispatch.put(find, "Format", "True");

		// 大小写匹配
		Dispatch.put(find, "MatchCase", "True");

		// 全字匹配
		Dispatch.put(find, "MatchWholeWord", "True");

		// 查找并选中
		return Dispatch.call(find, "Execute").getBoolean();

	}

	/**
	 * 
	 * 把选定内容替换为设定文本
	 * 
	 * 
	 * 
	 * @param selection
	 * 
	 *            Dispatch 选定内容
	 * 
	 * @param newText
	 * 
	 *            String 替换为文本
	 */

	public void replace(Dispatch selection, String newText, String tag) {
		// 设置替换文本
		Dispatch.put(selection, "Text", newText);

		// 加粗，斜体，下划线，颜色，大小，字体名
		if ("{序号}".equals(tag))
			setFont(true, false, false, null, "14", "仿宋_GB2312"); // word里的四号字体是14

		if ("{标题}".equals(tag))
			setFont(true, false, false, null, "14", "仿宋_GB2312");

		if ("{时间}".equals(tag))
			setFont(false, false, false, null, "14", "仿宋_GB2312");

		if ("{来源}".equals(tag))
			setFont(false, false, false, null, "14", "仿宋_GB2312");

		if ("{正文}".equals(tag))
			setFont(false, false, false, null, "14", "仿宋_GB2312");

		if ("{图片}".equals(tag))
			setFont(false, false, false, null, "14", "仿宋_GB2312");

	}

	/**
	 * 
	 * 全局替换
	 * 
	 * 
	 * @param selection
	 * 
	 *            Dispatch 选定内容或起始插入点
	 * 
	 * @param oldText
	 * 
	 *            String 要替换的文本
	 * 
	 * @param newText
	 * 
	 *            String 替换为文本
	 */

	public void replaceAll(Dispatch selection, String oldText, Object replaceObj) {
		// 移动到文件开头
		moveStart(selection);

		String newText = (String) replaceObj;

		while (find(selection, oldText)) {
			replace(selection, newText, oldText);
			Dispatch.call(selection, "MoveRight"); // 右移一位
		}
	}

	/**
	 * 
	 * 保存文件
	 * 
	 * @param outputPath
	 * 
	 *            String 输出文件（包含路径）
	 */

	public void save(String outputPath) {
		try {
			/* FileUtil. */buildDir(outputPath); // 先生成一个空文件
			Dispatch.call(Dispatch.call(word, "WordBasic").getDispatch(),
					"FileSaveAs", outputPath);
		} catch (Throwable e) {
			e.printStackTrace();
		}
		// Dispatch.call(document, "SaveAs", filename);
	}

	/**
	 * 
	 * 关闭文件
	 * 
	 * 
	 * 
	 * @param document
	 * 
	 *            Dispatch 要关闭的文件
	 */

	public void close(Dispatch doc) {
		Dispatch.call(doc, "Close", new Variant(saveOnExit));
	}

	/**
	 * 
	 * 根据模板、数据生成word文件
	 * 
	 * 
	 * 
	 * @param inputPath
	 * 
	 *            String 模板文件（包含路径）
	 * 
	 * @param outPath
	 * 
	 *            String 输出文件（包含路径）
	 * 
	 * @param data
	 * 
	 *            HashMap 数据包（包含要填充的字段、对应的数据）
	 */

	public void toWord(String inputPath, String outPath,
			HashMap<String, String> data) throws Exception {
		String oldText;

		Object newValue;

		try {
			init();

			doc = open(inputPath);

			Dispatch selection = select();

			Iterator<String> keys = data.keySet().iterator();
			while (keys.hasNext()) {
				oldText = (String) keys.next();

				if ("{图片}".equals(oldText)) {

					// 图片格式：e:\\xue.jpg,,,艺术总监莫尼卡;;;e:\\xue.jpg2,,,艺术总监莫尼卡
					String newVal = (String) data.get(oldText);
					if (newVal != null && !"".equals(newVal)) {
						String[] temp = newVal.split(";;;");

						if (temp != null && temp.length > 0) {

							// //插入图片，先将鼠标移到插图片的模板处
							if (find(selection, oldText)) {
								for (int i = 0; i < temp.length; i++) {
									if (temp[i] != null && !"".equals(temp[i])) {
										String[] line = temp[i].split(",,,");
										if (line != null && line.length > 0) {
											String picPath = line[0];

											String picDescrip = null;

											if (line.length > 1)
												picDescrip = line[1];

											if (picPath.indexOf(":") != -1) {
												insertImage(picPath); // 插入图片

												if (picDescrip != null) {
													replace(selection,
															picDescrip, oldText); // 插入图片描述
													insertln();
												}
											}

										}

									}

								}// end for
							}
						}
					} else {
						// 没有图片时将图片那个地方置为空
						if (find(selection, oldText)) {
							replace(selection, "", oldText);
						}
					}
				} else {
					newValue = data.get(oldText);
					replaceAll(selection, oldText, newValue);
				}
			}

			save(outPath);

			if (doc != null)
				close(doc);
		} catch (Exception e) {
			System.out.println("操作word文件失败！" + e);
			e.printStackTrace();
			throw new Exception("生成Word文件失败！原因:" + e.getMessage());
		} finally {
			if (word != null)

				word.invoke("Quit", new Variant[] {});
		}
	}

	/**
	 * 
	 * 
	 * 
	 * @param toFindText
	 * 
	 *            要查找的字符串
	 * 
	 * @param imagePath
	 * 
	 *            图片路径
	 * 
	 * @return
	 */

	public boolean replaceImage(String toFindText, String imagePath) {
		if (!find(select(), toFindText))
			return false;

		Dispatch.call(Dispatch.get(select(), "InLineShapes").toDispatch(),
				"AddPicture", imagePath);

		return true;
	}

	/**
	 * 
	 * 全局替换图片
	 * 
	 * 
	 * 
	 * @param toFindText
	 * 
	 *            查找字符串
	 * 
	 * @param imagePath
	 * 
	 *            图片路径
	 */

	public void replaceAllImage(String toFindText, String imagePath) {
		while (find(select(), toFindText)) {
			Dispatch.call(Dispatch.get(select(), "InLineShapes").toDispatch(),
					"AddPicture", imagePath);

			Dispatch.call(select(), "MoveRight");
		}
	}

	/**
	 * 
	 * 在当前插入点插入图片
	 * 
	 * 
	 * 
	 * @param imagePath
	 * 
	 *            图片路径
	 */

	public void insertImage(String imagePath) {
		Dispatch.call(Dispatch.get(select(), "InLineShapes").toDispatch(),
				"AddPicture", imagePath);

		// 居中显示
		Dispatch oAlign = Dispatch.get(select(), "ParagraphFormat")
				.toDispatch();

		Dispatch.put(oAlign, "Alignment", "1");
	}

	public void printing(String inPath, String outPath, HashMap map) {
		try {
			toWord(inPath, outPath, map);
		} catch (Exception e) {
			e.printStackTrace();

		}

		// //打印

		// ActiveXComponent objWord = new ActiveXComponent("Word.Application");

		// Dispatch wordObject = (Dispatch) objWord.getObject();

		// Dispatch.put((Dispatch) wordObject, "Visible", new Variant(false));

		// Dispatch documents = objWord.getProperty("Documents").toDispatch();

		// Dispatch document = Dispatch.call(documents, "Open",
		// outPath).toDispatch();

		// Dispatch.call(document, "PrintOut");

		// Dispatch.call(document, "Close", new Variant(false));

		// objWord.invoke("Quit",new Variant[0]);

		// word.invoke("Quit",new Variant[0]);

	}

	/**
	 * 
	 * 设置当前选定内容的字体
	 * 
	 * 
	 * 
	 * @param boldSize
	 * 
	 * @param italicSize
	 * 
	 * @param underLineSize
	 * 
	 *            下划线
	 * 
	 * @param colorSize
	 * 
	 *            字体颜色
	 * 
	 * @param size
	 * 
	 *            字体大小
	 * 
	 * @param name
	 * 
	 *            字体名称
	 */

	public void setFont(boolean bold, boolean italic, boolean underLine,
			String colorSize, String size, String name) {

		Dispatch font = Dispatch.get(select(), "Font").toDispatch();
		Dispatch.put(font, "Bold", new Variant(bold));
		Dispatch.put(font, "Italic", new Variant(italic));
		Dispatch.put(font, "Underline", new Variant(underLine));

		if (colorSize != null)
			Dispatch.put(font, "Color", colorSize);

		if (size != null)
			Dispatch.put(font, "Size", size);

		if (name != null)
			Dispatch.put(font, "Name", new Variant(name));

		// Dispatch.put(font, "Alignment", "1");

	}

	/** 合并WORD文档,第一个为要合并的文档 **/

	public static void uniteDoc(List fileList, String savepaths) {
		if (fileList.size() == 0 || fileList == null) {
			return;
		}

		// 打开word

		ActiveXComponent app = new ActiveXComponent("Word.Application");// 启动word

		try {
			// 设置word不可见
			app.setProperty("Visible", new Variant(false));

			// 获得documents对象
			Object docs = app.getProperty("Documents").toDispatch();

			// 打开第一个文件
			Dispatch doc = Dispatch
					.invoke(
							(Dispatch) docs,
							"Open",
							Dispatch.Method,
							new Object[] { (String) fileList.get(0),
									new Variant(false), new Variant(true) },
							new int[3]).toDispatch();

			// 追加文件
			for (int i = 1; i < fileList.size(); i++) {
				// Dispatch wordContent = Dispatch.get(doc,
				// "Content").toDispatch(); // 取得word文件的内容

				// Dispatch paragraphs = Dispatch.get(wordContent,
				// "Paragraphs").toDispatch(); // 所有段落

				// int paragraphCount = Dispatch.get(paragraphs,
				// "Count").toInt(); // 一共的段落数

				// Dispatch lastParagraph = Dispatch.call(paragraphs, "Item",new
				// Variant(paragraphCount)).toDispatch(); // 最后一段

				Dispatch.call(app.getProperty("Selection").toDispatch(),
						"HomeKey", new Variant(6));

				Dispatch.invoke(app.getProperty("Selection").toDispatch(),

				"insertFile", Dispatch.Method, new Object[] {

				(String) fileList.get(i), "",

				new Variant(false), new Variant(false),

				new Variant(false) }, new int[3]);

			}
			// 保存新的word文件
			/* FileUtil. */buildDir(savepaths);
			Dispatch.invoke((Dispatch) doc, "SaveAs", Dispatch.Method,
					new Object[] { savepaths, new Variant(1) }, new int[3]);
			Variant f = new Variant(false);
			Dispatch.call((Dispatch) doc, "Close", f);
		} catch (Exception e) {
			throw new RuntimeException("合并word文件出错.原因:" + e);
		} finally {
			app.invoke("Quit", new Variant[] {});
		}
	}

	/**
	 * 
	 * @param args
	 */

	public static void main(String[] args) {
		// *****************************************
		HashMap<String, String> map = new HashMap<String, String>();
		map.put("{序号}", "1");
		map.put("{标题}", "《曼侬》《睡美人》各演三天");
		map.put("{时间}", "2008年06月17日");
		map.put("{来源}", "京华时报");
		map.put("{图片}",
				"e:\\xue.jpg,,,被劫持的人质 版权作品，请勿转载;;;e:\\xue.jpg,,,艺术总监莫尼卡"); // 图片路径及图片描述

		// map.put("{图片}","e:\\xue.jpg,,,被劫持的人质 版权作品，请勿转载"); //图片路径及图片描述
		map
				.put(
						"{正文}",
						"国家大剧院昨天召开新闻发布会，宣布英国皇家芭蕾舞团将从6月18日开始，在国家大剧院演出9场芭蕾，其中被称为英国皇芭“镇团之宝”的《曼侬》，将首次在中国亮相，连续上演三场，该团的经典芭蕾舞剧《睡美人》在之后同样将满足观众的要求连演三场。");

		// ******************************************
		TestWord app = new TestWord();
		try {
			app.toWord("E:\\workspace3.3\\GnsClient\\conf\\template.doc",
					"e:\\大剧院1.doc", map);
		} catch (Exception e) {
			e.printStackTrace();
		}

		// app.printing("E:\\workspace3.3\\GnsClient\\conf\\template.doc",
		// "e:\\大剧院2.doc",map);

		// //合并文档

		// List<String> list = new ArrayList<String>();

		// list.add("e:\\大剧院2.doc");

		// list.add("E:\\workspace3.3\\GnsClient\\conf\\head.doc");

		// list.add("e:\\大剧院1.doc");

		//          

		// Java2word.uniteDoc(list, "e:\\大剧院.doc");

		System.out.println("生成Word完毕!");
	}

	private static void buildDir(String outputPath) {
		File f = new File(outputPath);
		if (!f.exists()) {
			f.mkdir();
		}
	}
}
